package quadTree;
/**
 * QuadNode.java
 * @author Kirk Roerig
 * 
 *	Node for the QuadTree data structure. Describes a finite space within
 *	the QuadTree.
 */
import java.util.LinkedList;
import quadTree.BoundingBox.IntersectRes;
import engine.PhysicsObject;


/*
 * @ public invariant children != null;
 * @ public invariant data !=null;
 * @ public invariant key !=null;
 */
public class QuadNode {
	private /*@ spec_public @*/ QuadTree tree;
	private /*@ spec_public @*/ QuadNode parent;
	private /*@ spec_public @*/ LinkedList<QuadNode> children;
	private /*@ spec_public @*/ int depth;
	private /*@ spec_public @*/ LinkedList<PhysicsObject> data;
	private /*@ spec_public @*/ BoundingBox key;
	/**
	 * QuadNode Constructor
	 * @param parent the parent of the new QuadNode
	 * @param key the BoundingBox used when searching for this QuadNode in the QuadTree
	 */
	/*
	 * @ requires key != null;
	 * @ ensures this.key != null;
	 * @ ensures this.data != null;
	 * @ ensures this.depth = this.parent.depth + 1;
	 * @ ensures this.children != null;
	 */
	public QuadNode(QuadNode parent, BoundingBox key){
		this.key = key;
		this.parent = parent;
		
		if(parent!=null)
			this.depth = parent.depth + 1;
		
		data = new LinkedList<PhysicsObject>();
		children = new LinkedList<QuadNode>();
	}

	/*
	 * @ requires tree != null;
	 * @ requires key != null;
	 * @ ensures this.key != null;
	 * @ ensures this.data != null;
	 * @ ensures this.tree != null;
	 * @ ensures this.depth = 0;
	 * @ ensures this.children != null;
	 */
	public QuadNode(QuadTree tree, BoundingBox key){
		this.key = key;
		this.parent = null;
		this.tree = tree;

		this.depth = 0;
		
		data = new LinkedList<PhysicsObject>();
		children = new LinkedList<QuadNode>();
	}
	/**
	 * addChild adds a child to the QuadNode's list of children
	 * @param child the child QuadNode to be added
	 */
	/*
	 * @ requires child != null;
	 * @ ensures child.parent == this;
	 * @ ensures child.depth == depth + 1;
	 * @ ensures children.size() > \old(children.size());
	 */
	public void addChild(QuadNode child){
		child.parent = this;
		child.depth = depth + 1;
		child.tree = this.tree;
		children.addLast(child);
		
		tree.size++;
	}
	/**
	 * compare Compares this QuadNode to another and QuadNode to determine the relation
	 * @param node the other QuadNode this one will be compared to
	 * @return whether this QuadNode's bounding box is disjoint, intersecting or contains the BoundingBox of the other QuadNode
	 */
	/*
	 * @ requires node != null;
	 * @ ensures \result >= 0 && \result <= 2;
	 */
	public IntersectRes compare(QuadNode node){
		return key.Contains(node.key);
	}
	
	/*
	 * Getters and setters
	 */
	
	
	/**
	 * getData Returns the list of PhysicsObjects used by the QuadNode
	 * @return the QuadNode's PhysicsObjects 
	 */
	/*
	 * @ returns data;
	 * @ ensures \result == this.data;
	 */
	public LinkedList<PhysicsObject> getData() {
		return data;
	}
	/**
	 * setData sets the QuadNode's list of PhysicsObjects to a specified list
	 * @param data the new list of PhysicsObjects to be used by the QuadNode
	 */
	/*
	 * @ assignable data;
	 * @ ensures this.data == data;
	 */
	public void setData(LinkedList<PhysicsObject> data) {
		this.data = data;
	}
	/**
	 * getParent Returns this QuadNode's parent in the QuadTree
	 * @return the QuadNode's parent
	 */
	/*
	 * @ returns parent;
	 * @ ensures \result == this.parent;
	 */
	public QuadNode getParent() {
		return parent;
	}
	/**
	 * getChildren returns a LinkedList of all the children of this QuadNode in the QuadTree
	 * @return this QuadNode's children
	 */
	/*
	 * @ returns children;
	 * @ ensures \result == this.children;
	 */
	public LinkedList<QuadNode> getChildren() {
		return children;
	}
	/**
	 * getDepth Returns the depth at which this node is found in the QuadTree
	 * @return the node's depth in the QuadTree
	 */
	/*
	 * @ returns depth;
	 * @ ensures \result == this.depth;
	 */
	public int getDepth() {
		return depth;
	}
	/**
	 * getKey returns the key of this QuadNode, its BoundingBox
	 * @return the key of this QuadNode
	 */
	/*
	 * @ returns key;
	 * @ ensures \result == this.key;
	 */
	public BoundingBox getKey() {
		return key;
	}
}
